﻿/// <reference path="../../jquery.d.ts"/>
/// <reference path="../../jquerymobile.d.ts"/>
/// <reference path="../../google.maps.d.ts" />
/// <reference path="../../geo.core.ts" />
/// <reference path="../../CoordinateConverter/Geo.CoordinateConverter.ts" />




//***********************************
// Core ViewModel                             
//***********************************
module Geo.ViewModel {
    export class Location {
        public static ViewModel: Geo.CoordinateConverter.CoordinateViewModel;

        private static _map: google.maps.Map;
        private static _mapCircle = new google.maps.Circle;
        private static _zooming: bool = false;
        private static _zoomingNow: bool = false;
        private static _zoomingCancelled: bool = false;

        public static LoadCoordinateError(err): void {
            alert(err);
        }
        public static IsAutomaticLocationOn(): bool {
            return $("#LocationTypeSwitch").val() === 'on';
        }
        public static Save(): void {
            var newLog: Geo.Interfaces.ILogEntry = Geo.Core.LogEntryRepository.Add(Geo.Core.Current, Geo.Enumerations.ActionTypes.DropOff,
                null, null, ViewModel.Model.ToCoordinateDecimal(), null);

            alert('Saved as ' + newLog.LogEntryLid);
        }
        
        public static CancelZooming(): void {
            _zoomingCancelled = true;
        }

        public static CoordinateChanged(): void {
            this._viewModel.Update();
            this.CancelZooming();
            Current.Scope.LocationWatchStop();
        }
        public static MapMarkerCenter(): void {
            if (this._mapCircle != null && this._mapCircle.getMap() != null)
                this._mapCircle.setCenter(this._map.getCenter());
        }
        public static MapMarkerReSize(): void {
            var radius: number = Math.pow(2, 22 - this._map.zoom);
            this._mapCircle.setRadius(radius);
            if (this._zooming && !this._zoomingNow) {
                this.CancelZooming();
            }
        }
        
        public static Initialize(): void {
            this._viewModel = new Geo.CoordinateConverter.CoordinateViewModel(new Geo.CoordinateConverter.Providers.DecimalAndDmsConverter(),
            <HTMLInputElement>document.getElementById('txtCoordinates'),
            <HTMLHeadingElement>document.getElementById('lblGps'),
            <HTMLHeadingElement>document.getElementById('lblDms'),
            <HTMLHeadingElement>document.getElementById('lblDecimalDegrees'),
            () => this.CoordinateChanged());

            Current.Scope.GetPosition();
        }

        public static GetCoordinatesFromMap() {
            var _mapCenter: google.maps.LatLng = _map.getCenter();
            var newPosition : Geo.CoordinateConverter.Interfaces.ICoordinateDecimal = new Geo.CoordinateConverter.Model.CoordinateDecimalInfo(_mapCenter.lat(),  _mapCenter.lng());
            this._viewModel.Update(newPosition.ToString());
        }

        public static GotPosition(position: Geo.CoordinateConverter.Interfaces.ICoordinateDms): void {
            var newPosition: string = position.ToString();
            this._viewModel.Update(newPosition);
            if (((navigator && navigator.onLine) || (!navigator && window.navigator.onLine)) && google) {
                if (this._map == null) {
                    this.CreateMap();
                    this.StartZoomIn(1, 21);
                } else {
                    this.CenterMap();
                    this.StartZoomIn(this._map.zoom, 21);
                }
            }
        }
        public static CreateMap(): void {
            var mapCanvas = document.getElementById('map-canvas');
            var mapContainer = document.getElementById('map-container');
            mapContainer.style.display = 'inline-block';
            this._map = new google.maps.Map(mapCanvas);
            this._map.addListener('mouseup',()=>Current.Scope.MapMouseUp());
            this._map.addListener('zoom_changed',()=>Current.Scope.MapZoomChanged());
            this._map.addListener('center_changed', ()=>Current.Scope.MapCenterChanged());

            this._mapCircle = new google.maps.Circle({
                center: this._map.center,
                radius: Math.pow(2, 22 - this._map.zoom),
                fillColor: '#FF0000',
                fillOpacity: 0.2
            });
            this._mapCircle.setMap(this._map);
        }
        public static CenterMap(): void  {
            var coordinateDecimal: Geo.CoordinateConverter.Interfaces.ICoordinateDecimal = this._viewModel.Model.ToCoordinateDecimal();
            this._map.setCenter(new google.maps.LatLng(coordinateDecimal.Latitude, coordinateDecimal.Longitude));
        }

        public static StartZoomIn(num: number, max: number) {
            if (_zooming)
                return;
            
            this._map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
            this.ZoomIn(num-1, max)
        }

        private static ZoomIn(num: number, max: number) {
            if (this._zoomingCancelled) {
                _zoomingCancelled = false;
                _zooming = false;
                return;
            }
            var newZoom = num + 1;
            this.CenterMap();
            if (newZoom < max) {
                this._zooming = true;
                this._zoomingNow = true;
                this._map.setZoom(newZoom);
                this._zoomingNow = false;
                Current.Scope.ZoomingIn(newZoom, max);
            } else {
                this._zooming = false;
                this._map.setMapTypeId(google.maps.MapTypeId.HYBRID);
            }
        }
    }

}
module Current {
    export class Scope {
        private static LocationWatch: number;
        private static ZoomingIn(num: number, max: number) {
            var to = setTimeout(function () {
                Geo.ViewModel.Location.ZoomIn(num, max);
            }, 1000);
        }

        public static GetPosition(): void {
            navigator.geolocation.getCurrentPosition((position) => {
                Geo.ViewModel.Location.GotPosition(new Geo.CoordinateConverter.Model.CoordinateDecimalInfo(position.coords.latitude, position.coords.longitude).ToCoordinateDms());
                Current.Scope.LocationWatchStart();
            }, (err) => {
                alert('Initialize navigator.geolocation.getCurrentPosition ERROR ' + err.message);
            }, { enableHighAccuracy: false, timeout: 30000, maximumAge: Infinity });
        }

        public static LocationWatchStart(): void {
            var LocationTypeSwitch = $('#LocationTypeSwitch');
            if (LocationTypeSwitch.val() === 'off') {
               LocationTypeSwitch.val('on').slider('refresh');
            }
            try {
                if (LocationWatch == null) {
                    LocationWatch = navigator.geolocation.watchPosition(function (position) {
                        Geo.ViewModel.Location.GotPosition(new Geo.CoordinateConverter.Model.CoordinateDecimalInfo(position.coords.latitude, position.coords.longitude).ToCoordinateDms());
                    },
                    function (err) {
                        LocationWatchStop();
                    },
                    { enableHighAccuracy: true, timeout: 15000, maximumAge: 30000 });
                }
            } catch (ex) {

            }
        }
        
        public static LocationWatchStop(): void {
            var LocationTypeSwitch = $('#LocationTypeSwitch');
            if (LocationTypeSwitch.val() === 'on') {
               LocationTypeSwitch.val('off').slider('refresh');
            }
            try {
                if (LocationWatch != null) {
                    navigator.geolocation.clearWatch(LocationWatch);
                    LocationWatch = null;
                }
            } catch (ex) {

            }
        }
        public static MapMouseUp(): void {
            Current.Scope.LocationWatchStop();
            Geo.ViewModel.Location.GetCoordinatesFromMap();
        }
        public static MapCenterChanged(): void {
            Geo.ViewModel.Location.MapMarkerCenter();
        }
        public static MapZoomChanged(): void {
            Geo.ViewModel.Location.MapMarkerReSize();
        }
        
            

    }
    Geo.Core.OnAfterInitialize.add(function () {
        if (Geo.Core.Current.PrivateKey === null) {
            Geo.Core.Navigation.GoToEntry();
            return;
        } else if (Geo.Core.Current.ActionType === null) {
            Geo.Core.Navigation.GoToAction();
            return;
        }

        Geo.ViewModel.Location.Initialize();

        $('#btnNext').bind('click', function () {
            if (Geo.Core.Current.LogEntryLid) {
                Geo.Core.Current.Coordinates = Geo.ViewModel.Location.ViewModel.Model.ToCoordinateDecimal();
                Geo.Core.LogEntryRepository.Update(Geo.Core.Current);
            } else {
                Geo.ViewModel.Location.Save();
            }
            Geo.Core.Navigation.GoToView();
            return false;
        });

        $('#btnBack').bind('click', function () {
            if (Geo.Core.Current.LogEntryLid)
                Geo.Core.Navigation.GoToAction();
            else
                Geo.Core.Navigation.GoToActionDetail(Geo.Core.Current.ActionType);
            return false;
        });

         $("#LocationTypeSwitch").change(function () {
                if ($(this).val() === 'on') {
                    Current.Scope.LocationWatchStart();
                } else {
                    Current.Scope.LocationWatchStop();
                }
         });


    });
}
